import heapq
from collections import namedtuple

import numpy as np

from .seg import cut_text
from .vector import WordVec 
from .sim import CosSimilar as Similar 
from .corpus import XhjCorpus, XhjClusterCorpus
 

AnswerItem = namedtuple("AnswerItem", ["sim", "question", "answer"])


class ChatBot:
    """
    Attributes
    ----------
    N_SAMPLE : 从总语料中随机抽取的样本书量
    corpus : 语料
    similar : 相似度计算的类实例
    wordvec : 文本转为向量的类实例
    """

    def __init__(self, wv=None):
        """
        Args
        ----
        wv : 由gensim加载而来的词向量
        """
        self.N_SAMPLE = 6000
        self.similar = Similar()
        self.wordvec = wordvec = WordVec(wv_model=wv)
        self.corpus = XhjClusterCorpus(wordvec)
        #self.corpus = XhjCorpus()

    def text2vec(self, text):
        """文本分词，并转为向量
        """
        doc = cut_text(text)
        vec = self.wordvec.doc2vec(doc)
        return vec

    def get_answer_item(self, question, threshold=0.6):
        """ 根据相似度从语料中找到最相近的question，并返回该question的回答
        Args
        ----
        question : str, 问题
        threshold : 相似度阈值， 回答必须大于该阈值
        
        Returns
        -------
        answer : AnswerItem 元组
        """
        #将question转为向量
        question_vec = self.text2vec(question)
        # 从corpus中抽取部分样本
        samples_index = self.corpus.take_samples(self.N_SAMPLE, question)
        samples_question = self.corpus.get_question(samples_index)
        samples_question_vec = self.wordvec.docs2vec(samples_question)
        # 匹配一条记录
        sim, ind = self.similar.match_one(question_vec, samples_question_vec, threshold)
        if sim is None:
            return AnswerItem(None, None, "没听懂你在说什么")
        # 返回匹配结果
        matched_index =  samples_index[ind]
        matched_question = self.corpus.get_question(matched_index)
        matched_answer = self.corpus.get_answer(matched_index)
        return AnswerItem(sim, matched_question, matched_answer)

    def get_answer(self, question, threshold=0.6):
        """返回question答案
        """
        item = self.get_answer_item(question, threshold)
        return item.answer
            
